From 09ca9fa27ac752ebd3368d73a46158fb2ac5af09 Mon Sep 17 00:00:00 2001 From: robertl Date: Wed, 29 Jun 2005 18:48:54 +0000 Subject: [PATCH] Oops. Forgot bcr.c --- gpsbabel/bcr.c | 547 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 547 insertions(+) create mode 100644 gpsbabel/bcr.c diff --git a/gpsbabel/bcr.c b/gpsbabel/bcr.c new file mode 100644 index 000000000..06ba79cfb --- /dev/null +++ b/gpsbabel/bcr.c @@ -0,0 +1,547 @@ +/* + + Support for Motorrad Routenplaner (Map&Guide) .bcr files. + + Copyright (C) 2005 Olaf Klein, o.b.klein@t-online.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + + +#include "defs.h" +#include "garmin_tables.h" +#include +#include +#include +#include + + +#define MYNAME "bcr" + +#define BCR_DEBUG +// #undef BCR_DEBUG + +#define SEC_UNKNOWN 0 +#define SEC_CLIENT 1 +#define SEC_ROUTE 2 +#define SEC_DESCR 3 +#define SEC_COORD 4 + +#define R_EARTH 6371000 /* radius of our big blue ball */ + +/* + 6371014 would be a better value when converting to f.e. to mapsoure, + but this seems to be used by Map&Guide when exporting to XML. +*/ + +static FILE *fin, *fout; +char *filename; +int curr_rte_num, target_rte_num; +static double radius; + +/* placeholders for options */ + +static char *rtenum_opt; +static char *rtename_opt; +static char *radius_opt; + +static +arglist_t bcr_args[] = { + {"index", &rtenum_opt, "Index of route to write (if more the one in source)", NULL, ARGTYPE_INT }, + {"name", &rtename_opt, "New name for the route", NULL, ARGTYPE_STRING }, + {"radius", &radius_opt, "Radius of our big earth (default 6371000 meters)", NULL, ARGTYPE_FLOAT }, + {0, 0, 0, 0, 0} +}; + +void +bcr_init_radius(void) +{ + if (radius_opt != NULL) /* preinitialize the earth radius */ + { + radius = atof(radius_opt); + if (radius < 0) + fatal(MYNAME ": Sorry, the radius should be greater than zero!\n"); + } + else + radius = (double)R_EARTH; + + if (global_opts.verbose_status > 0) + printf(MYNAME ": We calculate with radius %f meters.\n", radius); +} + +static void +bcr_rd_init(const char *fname) +{ + filename = xstrdup(fname); + fin = xfopen(fname, "r", MYNAME); + bcr_init_radius(); +} + +static void +bcr_rd_deinit(void) +{ + fclose(fin); + xfree(filename); +} + +/* ------------------------------------------------------------*/ + +char * +bcr_next_char(const char *buff) +{ + char *result = (char *)buff; + while (*result > '\0' && *result <= ' ') result++; /* trim leading spaces */ + return result; +} + +waypoint * +bcr_find_waypt(const char *name, route_head *route) /* find a waypt by name, create new */ +{ /* if not found */ + waypoint *wpt; + queue *elem, *tmp; + + QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) + { + wpt = (waypoint *) elem; + if (0 == strcmp(wpt->shortname, name)) + return wpt; + } + wpt = waypt_new(); + wpt->shortname = xstrdup(name); + + return wpt; +} + +#ifndef UTF8_SUPPORT +char * +bcr_iso8859_1_to_utf8(const char *s) +{ + int len; + char *res; + unsigned char c; + char *src, *dst; + + if (s == NULL) return NULL; + + len = 0; + src = (char *)s; + while ('\0' != (c = *src++)) + { + len++; + if (c & 0x80) len++; + } + + src = (char *)s; + dst = res = (void *) xmalloc(len + 1); + while ('\0' != (c = *src++)) + { + if (c & 0x80) + { + *dst++ = (0xc0 | (c >> 6)); + *dst++ = (c & 0xbf); + } + else + { + *dst++ = c; + } + } + *dst = '\0'; + return res; +} +#endif + +void +bcr_create_waypts_from_route(route_head *route) +{ + waypoint *wpt; + queue *elem, *tmp; + + QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) + { + wpt = waypt_dupe((waypoint *) elem); + waypt_add(wpt); + } +} + +void +bcr_wgs84_to_mercator(const double lat, const double lon, int *north, int *east) +{ + double N, E; + + N = log(tan(lat * M_PI / 360 + M_PI / 4)) * radius; + E = lon * radius * M_PI / (double)180; + + if (lat > 0) N += 0.500000000001; /* we go from double to integer */ + else N -= 0.500000000001; /* it's time to round a little bit */ + if (lon > 0) E += 0.500000000001; + else E -= 0.500000000001; + + *north = N; + *east = E; +} + +void +bcr_mercator_to_wgs84(const int north, const int east, double *lat, double *lon) +{ + *lat = 2 * (atan(exp(north / radius)) - M_PI / 4) / M_PI * (double)180; + *lon = (double)east * (double)180 / (radius * M_PI); +} + +static int +bcr_sort_route_by_index_cb(const void *a, const void *b) +{ + const waypoint *wa = *(waypoint **)a; + const waypoint *wb = *(waypoint **)b; + return wa->centiseconds - wb->centiseconds; +} + +route_head * +bcr_sort_route_by_index(route_head *route) +{ + route_head *result; + queue *elem, *tmp; + waypoint **list; + waypoint *wpt; + int i; + int count = route->rte_waypt_ct; + + if (count == 0) return (route); /* nothing to do */ + + result = route_head_alloc(); + result->rte_name = xstrdup(route->rte_name); + route_add_head(result); + + list = (waypoint **) xcalloc(route->rte_waypt_ct, sizeof(*list)); + i = 0; + QUEUE_FOR_EACH((queue *)&route->waypoint_list, elem, tmp) + { + wpt = (waypoint *)elem; + list[i++] = wpt; + } + qsort(list, route->rte_waypt_ct, sizeof(*list), bcr_sort_route_by_index_cb); + for (i=0; icentiseconds = 0; /* reset our index container */ + route_add_wpt(result, waypt_dupe(wpt)); + route_del_wpt(route, wpt); + } + + xfree(list); + route_del_head(route); + + return result; +} + +/* ------------------------------------------------------------- */ + +static void +bcr_data_read(void) +{ + char buff[1024]; + char *src; + int section = SEC_UNKNOWN; + char *c, *cx, *ctemp; + int index; + int mlat, mlon; /* mercator data */ + double xalt; + int line, skip; + + route_head *route; + waypoint *wpt; + + route = route_head_alloc(); + route_add_head(route); + + line = skip = 0; + src = NULL; + + while (NULL != fgets(buff, sizeof(buff), fin)) + { + line++; + + c = buff; /* trim the end of the buffer */ + cx = c + strlen(c) - 1; + while ((cx > c) && (*cx <= ' ')) + { + *cx = '\0'; + cx--; + } + if (src != NULL) xfree(src); + +#ifdef UTF8_SUPPORT + src = str_iso8859_1_to_utf8(buff); +#else + src = bcr_iso8859_1_to_utf8(buff); /* internal copy str_iso8859_1_to_utf8 */ +#endif + /* !! buff is now free and can be used */ + + c = bcr_next_char(src); /* skip spaces */ + if (*c == '\0') continue; /* skip empty lines */ + + if (*c == '[') /* new section */ + { + skip = 0; + + c = bcr_next_char(++c); + cx = strchr(c, ']'); + if (cx == NULL) fatal(MYNAME ": error in file structure (\"]\" expected)!\n"); + + *cx = '\0'; + if (strcmp(c, "CLIENT") == 0) section = SEC_CLIENT; + else if (strcmp(c, "ROUTE") == 0) section = SEC_ROUTE; + else if (strcmp(c, "DESCRIPTION") == 0) section = SEC_DESCR; + else if (strcmp(c, "COORDINATES") == 0) section = SEC_COORD; + else + { + printf(MYNAME ": unknown section \"%s\".\n", c); + skip = 1; + } + continue; + } + + if (skip != 0) continue; + + cx = strchr(c, '='); + if (cx == NULL) continue; + + *cx++ = '\0'; /* delimit in key and data */ + + if ((section == SEC_CLIENT) && (strcmp(c, "ROUTENAME") == 0)) + { + route->rte_name = xstrdup(cx); + } + else + { + if (strncmp(c, "STATION", 7) != 0) continue; + index = atoi(c+7); + + /* bcr_find_waypt(... creates new waypoint, if not in queue */ + + switch(section) + { + case SEC_CLIENT: + wpt = bcr_find_waypt(c, route); + wpt->centiseconds = index; + ctemp = strchr(cx, ','); + if (ctemp != NULL) *ctemp = ' '; + if (2 != sscanf(cx, "%s %lf", buff, &xalt)) + fatal(MYNAME ": structure error on line %d!\n(data: %s=%s)\n", line, c, cx); +#if 0 + if (xalt != 999999999) + wpt->altitude = xalt / 3.2808; /* convert feet to meters */ +#endif + route_add_wpt(route, wpt); + + if (case_ignore_strcmp(buff, "standort") == 0) + wpt->icon_descr = mps_find_desc_from_icon_number(18, MAPSOURCE); + else if (case_ignore_strcmp(buff, "Town") == 0) + wpt->icon_descr = mps_find_desc_from_icon_number(69, MAPSOURCE); + else + printf(MYNAME ": Unknown icon \"%s\" found. Please report.\n", buff); + break; + + case SEC_DESCR: + wpt = bcr_find_waypt(c, route); + wpt->centiseconds = index; + + ctemp = strchr(cx, '@'); + if (ctemp != NULL) + { + *ctemp-- = '\0'; + if (*ctemp == ',') *ctemp = '\0'; + } + wpt->description = xstrdup(cx); + break; + + case SEC_COORD: + wpt = bcr_find_waypt(c, route); + wpt->centiseconds = index; + if (2 != sscanf(cx, "%d,%d", &mlon, &mlat)) + fatal(MYNAME ": structure error on line %d!\n", line); + + bcr_mercator_to_wgs84(mlat, mlon, &wpt->latitude, &wpt->longitude); + case SEC_ROUTE: + break; + } + } + } + if (src != NULL) xfree(src); + src = NULL; + + route = bcr_sort_route_by_index(route); + bcr_create_waypts_from_route(route); +} + +/* %%% bcr write support %%% ----------------------------------- */ + +static void +bcr_wr_init(const char *fname) +{ + filename = xstrdup(fname); + fout = xfopen(fname, "w", MYNAME); + bcr_init_radius(); +} + +static void +bcr_wr_deinit(void) +{ + fclose(fout); + xfree(filename); +} + +static void +bcr_route_trailer(const route_head *rte) +{ +} + +static void +bcr_write_wpt(const waypoint *wpt) +{ +} + +void bcr_write_line(FILE *fout, const char *key, int *index, const char *value) +{ + if (value == NULL) /* this is mostly used in the world of windows */ + { /* so we respectfully add a CR/LF on each line */ + fprintf(fout, "%s\x0d\n", key); + } + else + { + if (index != NULL) + fprintf(fout, "%s%d=%s\x0d\n", key, *index, value); + else + fprintf(fout, "%s=%s\x0d\n", key, value); + } +} + +static void +bcr_route_header(const route_head *route) +{ + queue *elem, *tmp; + waypoint *wpt; + char *c; + int i, icon, north, east, nmin, nmax, emin, emax; + char buff[128], symbol[32]; + + curr_rte_num++; + if (curr_rte_num != target_rte_num) return; + + + bcr_write_line(fout, "[CLIENT]", NULL, NULL); /* client section */ + + bcr_write_line(fout, "REQUEST", NULL, "TRUE"); + + c = route->rte_name; + if (rtename_opt != 0) c = rtename_opt; + if (c != NULL) + bcr_write_line(fout, "ROUTENAME", NULL, c); + else + bcr_write_line(fout, "ROUTENAME", NULL, "Route"); + + bcr_write_line(fout, "DESCRIPTIONLINES", NULL, "1"); + bcr_write_line(fout, "DESCRIPTION1", NULL, ""); + + i = 0; + QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) + { + i++; + wpt = (waypoint *) elem; + + strncpy(symbol, "Standort", sizeof(symbol)); + if (wpt->icon_descr != 0) + { + icon = mps_find_icon_number_from_desc(wpt->icon_descr, MAPSOURCE); + if ((icon >= 69) && (icon <= 72)) + strncpy(symbol, "Town", sizeof(symbol)); + } + snprintf(buff, sizeof(buff), "%s,%s", symbol, "999999999"); + bcr_write_line(fout, "STATION", &i, buff); + } + + bcr_write_line(fout, "[COORDINATES]", NULL, NULL); /* coords section */ + + nmin = emin = (1<<30); + emax = nmax = -nmin; + + i = 0; + QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) + { + i++; + wpt = (waypoint *) elem; + + bcr_wgs84_to_mercator(wpt->latitude, wpt->longitude, &north, &east); + + if (north > nmax) nmax = north; + if (east > emax) emax = east; + if (north < nmin) nmin = north; + if (east < emin) emin = east; + + snprintf(buff, sizeof(buff), "%d,%d", east, north); + bcr_write_line(fout, "STATION", &i, buff); + } + + bcr_write_line(fout, "[DESCRIPTION]", NULL, NULL); /* descr. section */ + + i = 0; + QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) + { + i++; + wpt = (waypoint *) elem; + c = wpt->description; + if (c == NULL) c = wpt->shortname; + bcr_write_line(fout, "STATION", &i, c); + } + + bcr_write_line(fout, "[ROUTE]", NULL, NULL); /* route section */ + + snprintf(buff, sizeof(buff), "%d,%d,%d,%d", emin, nmax, emax, nmin); + bcr_write_line(fout, "ROUTERECT", NULL, buff); + +} + +static void +bcr_data_write(void) +{ + + if (global_opts.objective == rtedata) + { + target_rte_num = 1; + + if (rtenum_opt != NULL) + { + target_rte_num = atoi(rtenum_opt); + if ((target_rte_num > route_count()) || (target_rte_num < 1)) + fatal(MYNAME ": invalid route number %d (1..%d))!\n", + target_rte_num, route_count()); + } + curr_rte_num = 0; + route_disp_all(bcr_route_header, bcr_route_trailer, bcr_write_wpt); + } +} + +ff_vecs_t bcr_vecs = { + ff_type_file, + { ff_cap_none, ff_cap_read || ff_cap_write, ff_cap_none }, + bcr_rd_init, + bcr_wr_init, + bcr_rd_deinit, + bcr_wr_deinit, + bcr_data_read, + bcr_data_write, + NULL, + bcr_args +}; + -- 2.30.2